package cn.zjutleo.village_server.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.zjutleo.village_server.config.WechatConfig;
import cn.zjutleo.village_server.dto.WechatAccessTokenDto;
import cn.zjutleo.village_server.dto.WechatCheckResultDto;
import cn.zjutleo.village_server.dto.WechatDto;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @author : Qin Zhenghan
 * @date : Created in 2021/8/15
 * @description: 微信工具类
 */
@Slf4j
@Component
public class WechatUtil {
    @Resource
    private WechatConfig wechatConfig;

    /**
     * 获取openid的url
     */
    private static final String WECHAT_AUTH_URL_FORMAT = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&grant_type=authorization_code&js_code=%s";

    /**
     * 获取accessToken的url
     */
    public static final String ACCESS_TOKEN_URL_FORMAT = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    /**
     * 检测文本合法性url
     */
    public static final String MESSAGE_SEC_CHECK_URL_FORMAT = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=%s";

    private static final RestTemplate REST_TEMPLATE = new RestTemplate();

    private static String accessToken;

    /**
     * 内容可能存在风险的错误码
     */
    private static final Integer ERR_CODE = 87014;

    /**
     * 传入微信请求code返回授权校验结果
     *
     * @param code 微信请求code
     * @return 包含了各种校验信息的Map
     */
    public static WechatDto getWxInfo(String code, String appid, String secret) throws JsonProcessingException {
        //发送post请求读取调用微信接口获取openid用户唯一标识
        String requestUrl = String.format(WECHAT_AUTH_URL_FORMAT, appid, secret, code);
        ResponseEntity<String> responseEntity = REST_TEMPLATE.postForEntity(requestUrl, null, String.class);
        String responseStr = responseEntity.getBody();
        return JSONUtil.toBean(responseStr, WechatDto.class);
    }

    /**
     * 检测文本的合法性
     *
     * @param content 文本内容
     * @return true-文本合法 false-文本不合法
     */
    public static boolean checkContent(String content) {
        if (StrUtil.length(content) <= 1) {
            return true;
        }
        String requestUrl = String.format(MESSAGE_SEC_CHECK_URL_FORMAT, accessToken);
        WechatCheckResultDto resultDto;

        try {
            String requestBody = JSONUtil.createObj().put("content", content).toString();
            String postUrl = HttpUtil.post(requestUrl, requestBody);

            resultDto = JSONUtil.toBean(postUrl, WechatCheckResultDto.class);

            if (resultDto == null || resultDto.getErrcode() == null) {
                throw new Exception("检查结果为空");
            }

            if (resultDto.getErrcode().equals(0)) {
                return true;
            }
            // 只有当结果为不合法时才返回false
            if (resultDto.getErrcode().equals(ERR_CODE)) {
                log.warn("检测到违规内容：{}", content);
                return false;
            }

        } catch (Exception e) {
            log.error("微信文本检测失败，异常信息:{}", e.getMessage());
            return true;
        }

        log.error("异常的检测结果: {}", resultDto);
        return true;
    }

    /**
     * 定时刷新accessToken
     */
    @Scheduled(initialDelay = 1000, fixedDelay = 7100 * 1000)
    private void refreshAccessToken() {
        String requestUrl = String.format(ACCESS_TOKEN_URL_FORMAT, wechatConfig.getAppid(), wechatConfig.getSecret());

        WechatAccessTokenDto accessTokenDto = REST_TEMPLATE.getForObject(requestUrl, WechatAccessTokenDto.class);

        if (accessTokenDto == null) {
            log.error("获取微信accessToken异常，返回结果为空");
        } else if ((accessToken = accessTokenDto.getAccessToken()) == null) {
            log.error("获取微信accessToken异常,错误码:{} 错误信息:{}", accessTokenDto.getErrcode(), accessTokenDto.getErrmsg());
        }

    }
}